package org.yuezejian.alarm.netty;


import com.alibaba.fastjson.JSON;
import org.yuezejian.alarm.netty.channel.TCPCustomChannelInitializer;
import org.yuezejian.alarm.netty.channel.UDPCustomChannelInitializer;
import org.yuezejian.alarm.netty.channel.WebsocketCustomChannelInitializer;
import org.yuezejian.alarm.netty.channel.pool.AbstractChannelPool;
import org.yuezejian.alarm.netty.channel.pool.TCPChannelPool;
import org.yuezejian.alarm.netty.channel.pool.UDPChannelPool;
import org.yuezejian.alarm.netty.channel.pool.WebSocketChannelPool;
import org.yuezejian.alarm.netty.enums.ClientType;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 管理多个NettyClient
 *
 * @author yuezejian
 * @since 2024.8.1
 */
@Component
@Slf4j
public class MultiNettyClientManager {
    private final Map<String, AbstractChannelPool> channelPools = new HashMap<>();

    @Autowired
    private TCPCustomChannelInitializer tcpChannelInitializer;

    @Autowired
    private WebsocketCustomChannelInitializer wsChannelInitializer;
    @Autowired
    private UDPCustomChannelInitializer udpChannelInitializer;

    /**
     * 添加新客户端
     *
     * @param clientId    唯一ID
     * @param host
     * @param port
     * @param handlerType 实现的某Handler类名
     * @param clientType  TCP或WEBSOCKET
     * @throws InterruptedException
     */
    public synchronized void addClient(String clientId, String host, int port, String handlerType, ClientType clientType) throws InterruptedException {
        if (channelPools.containsKey(clientId)) {
            throw new IllegalArgumentException("Client with ID " + clientId + " already exists.");
        }

        AbstractChannelPool abstractChannelPool;
        switch (clientType) {
            case TCP:
                tcpChannelInitializer.setHandlerType(handlerType);
                abstractChannelPool = new TCPChannelPool(host, port, tcpChannelInitializer);
                break;
            case WEBSOCKET:
                wsChannelInitializer.setHandlerType(handlerType);
                abstractChannelPool = new WebSocketChannelPool(host, port, wsChannelInitializer);
                break;
            case UDP:
                udpChannelInitializer.setHandlerType(handlerType);
                abstractChannelPool = new UDPChannelPool(host, port, udpChannelInitializer);
                break;
            default:
                throw new IllegalArgumentException("Unsupported client type: " + clientType);
        }

        channelPools.put(clientId, abstractChannelPool);

        // 启动连接
        acquireChannel(clientId);
    }

    /**
     * 获取可用的Channel
     *
     * @param clientId
     * @return
     * @throws InterruptedException
     */
    public Channel acquireChannel(String clientId) throws InterruptedException {
        AbstractChannelPool abstractChannelPool = channelPools.get(clientId);
        if (abstractChannelPool == null) {
            throw new IllegalArgumentException("Client with ID " + clientId + " does not exist.");
        }
        log.info("abstractChannelPool" + JSON.toJSONString(abstractChannelPool));
        return abstractChannelPool.acquireChannel();
    }

    /**
     * 释放
     *
     * @param clientId
     * @param channel
     */
    public void releaseChannel(String clientId, Channel channel) {
        if (channel == null) {
            throw new IllegalArgumentException("Channel cannot be null.");
        }

        AbstractChannelPool abstractChannelPool = channelPools.get(clientId);
        if (abstractChannelPool == null) {
            throw new IllegalArgumentException("Client with ID " + clientId + " does not exist.");
        }

        abstractChannelPool.releaseChannel(channel);
    }

    /**
     * 优雅关闭所有连接池
     */
    public void shutdownAll() {
        for (AbstractChannelPool abstractChannelPool : channelPools.values()) {
            abstractChannelPool.shutdown(); // 优雅关闭所有连接池
        }
        channelPools.clear(); // 清空连接池列表
    }

    /**
     * 移除指定客户端
     *
     * @param clientId
     */
    public void removeClient(String clientId) {
        AbstractChannelPool abstractChannelPool = channelPools.remove(clientId);
        if (abstractChannelPool != null) {
            abstractChannelPool.shutdown(); // 关闭客户端连接池
        } else {
            throw new IllegalArgumentException("Client with ID " + clientId + " does not exist.");
        }
    }
}
